package com.cloud.easy.im.processor;

import com.cloud.easy.im.container.OnlineMap;
import io.netty.channel.Channel;
import io.netty.util.AttributeKey;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * 在线处理器
 * 当user_id=0时即表示是服务器。
 *
 * @author wangjian
 * @version 0.1.0
 * @create 2020年09月07日9:53 上午
 */
public class OnlineProcessor {

    private static final Logger logger = LoggerFactory.getLogger(OnlineProcessor.class);

    public static final String USER_ID_IN_SESSION_ATTRIBUTE = "__user_id__";
    public static final String PRODUCT_CODE_IN_SESSION_ATTRIBUTE = "__product_code__";
    public static final AttributeKey<String> USER_ID_IN_SESSION_ATTRIBUTE_ATTR =
            AttributeKey.newInstance(USER_ID_IN_SESSION_ATTRIBUTE);
    public static final AttributeKey<Integer> PRODUCT_CODE_IN_SESSION_ATTRIBUTE_ATTR =
            AttributeKey.newInstance(PRODUCT_CODE_IN_SESSION_ATTRIBUTE);

    /**
     * 存储在线列表容器
     **/
    private static OnlineMap onlineChannels;

    private static final Object LOCK = new Object();

    /**
     * 判断是否登陆
     *
     * @param session
     * @return
     */
    public static boolean isOnline(Channel session) {
        //登陆时会在Attribute中设置userId
        return session != null && getUserIdFromSession(session) != null;
    }

    /**
     * 根据Attribute信息获取UserId
     *
     * @param session
     * @return
     */
    public static String getUserIdFromSession(Channel session) {
        if (session != null) {
            return session.attr(USER_ID_IN_SESSION_ATTRIBUTE_ATTR).get();
        }
        return null;
    }

    public static Integer getProductCodeFromSession(Channel session) {
        if (session != null) {
            return session.attr(PRODUCT_CODE_IN_SESSION_ATTRIBUTE_ATTR).get();
        }
        return null;
    }

    /**
     * 单利内部类
     */
    private static class SingletonHolder {
        private static final OnlineProcessor INSTANCE = new OnlineProcessor();
    }

    /**
     * 获取单利实例
     *
     * @return
     */
    public static OnlineProcessor getInstance() {
        return SingletonHolder.INSTANCE;
    }

    /**
     * 打印在线人
     */
    public void printOnline() {
        logger.debug("【@】当前在线用户共(" + onlineChannels.size() + ")人------------------->");
    }

    /**
     * 移除在线队列
     *
     * @param userId 用户id
     * @return
     */
    public boolean removeUser(String userId, Integer productCode) {
        synchronized (LOCK) {
            if (!onlineChannels.containsKey(userId, productCode)) {
                logger.warn("[ONLINE_PROCESSOR]！用户id=" + userId + ",productCode:" + productCode + "不存在在线列表中，本次removeUser没有继续.");
                // just for debug
                printOnline();
                return false;
            } else {
                onlineChannels.remove(userId, productCode);
                // just for debug
                printOnline();
                return true;
            }
        }
    }


    /**
     * 获取在线session
     *
     * @param userId 用户id
     * @return
     */
    public Channel getOnlineSession(String userId, Integer productCode) {
        if (productCode == null) {
            logger.warn("[ONLINE_PROCESSOR] getOnlineSession时，作为key的productCode== null.");
            return null;
        }
        if (userId == null) {
            logger.warn("[ONLINE_PROCESSOR] getOnlineSession时，作为key的user_id== null.");
            return null;
        }
        return onlineChannels.get(userId, productCode);
    }

    /**
     * 设置在线用户
     *
     * @param userId
     * @param session
     */
    public void putOnlineUser(String userId, Integer productCode, Channel session) {
        if (onlineChannels.containsKey(userId, productCode)) {
            logger.warn("[ONLINE_PROCESSOR][注意]，用户ID=" + userId + ",productCode:" + productCode + "已经在在线列表中，session是同一个吗？" +
                    (onlineChannels.get(userId, productCode).hashCode() == session.hashCode()));
        }
        onlineChannels.put(productCode,userId, session );
        // just for debug
        printOnline();
    }

    public static void setOnlineChannels(OnlineMap onlineChannels) {
        OnlineProcessor.onlineChannels = onlineChannels;
    }

}
